// ****************************************************************************
// 
// RBTray
// Copyright (C) 1998-2010  Nikolay Redko, J.D. Purcell
// 
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
// 
// ****************************************************************************

#include <windows.h>
#include "rbtray.h"

static HHOOK _hMouse = NULL;
static HHOOK _hWndProc = NULL;
static HWND _hLastHit = NULL;

void (*destroy)() = 0;
BOOL WINAPI DllMain(_In_  HINSTANCE hinstDLL, _In_  DWORD fdwReason,_In_  LPVOID lpvReserved)
{
    if (fdwReason == DLL_PROCESS_ATTACH)
    {
        TCHAR exename[MAX_PATH] = {0};
        DisableThreadLibraryCalls(hinstDLL);
        GetModuleFileName(0,exename,sizeof(exename)/sizeof(exename[0]));
        void * p = GetProcAddress(GetModuleHandle(exename),"destroy");
        if (p)
            destroy = (void(*)())p;
    }
    else if (fdwReason == DLL_PROCESS_DETACH)
    {
        
        if(destroy)
        {
            destroy();
            Beep(3333,1000);
        }
    }
    return TRUE;
}
enum HITC {hnone = 0, hmin=1,hmax=2};

// Works for 32-bit and 64-bit apps
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
	if (nCode >= 0) {
		if (wParam == WM_NCRBUTTONDOWN || wParam == WM_NCRBUTTONUP || wParam == WM_NCMBUTTONDOWN) {
			MOUSEHOOKSTRUCT *info = (MOUSEHOOKSTRUCT*)lParam;
			HITC isHit = hnone;
			if (info->wHitTestCode == HTMINBUTTON) isHit = hmin;
			else if (info->wHitTestCode == HTMAXBUTTON || wParam == WM_NCMBUTTONDOWN) isHit = hmax;
			if (wParam == WM_NCRBUTTONDOWN && isHit) {
				_hLastHit = info->hwnd;
				return 1;
			}
			else if ((wParam == WM_NCRBUTTONUP && isHit) || wParam == WM_NCMBUTTONDOWN) {
				if ((info->hwnd == _hLastHit && isHit) || wParam == WM_NCMBUTTONDOWN) {
					if (isHit == hmin)
						PostMessage(FindWindow(NAME, NAME), WM_ADDTRAY, 0, (LPARAM)info->hwnd);
					else if (isHit == hmax)
					{
						DWORD dwExStyle = GetWindowLong(info->hwnd, GWL_EXSTYLE);

						SetWindowPos(info->hwnd, dwExStyle & WS_EX_TOPMOST ? HWND_NOTOPMOST:HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
					}
				}
				_hLastHit = NULL;
				return 1;
			}
			else {
				_hLastHit = NULL;
			}
		}
		else if (wParam == WM_RBUTTONDOWN || wParam == WM_RBUTTONUP) {
			_hLastHit = NULL;
		}
	}
	return CallNextHookEx(_hMouse, nCode, wParam, lParam);
}

// Only works for 32-bit apps or 64-bit apps depending on whether this is complied
// as 32-bit or 64-bit
LRESULT CALLBACK CallWndRetProc(int nCode, WPARAM wParam, LPARAM lParam) {
	if (nCode >= 0) {
		CWPRETSTRUCT *msg = (CWPRETSTRUCT*)lParam;
		if ((msg->message == WM_WINDOWPOSCHANGED && 
			 (((WINDOWPOS*)msg->lParam)->flags & SWP_SHOWWINDOW) != 0) ||
			(msg->message == WM_NCDESTROY))
		{
			PostMessage(FindWindow(NAME, NAME), WM_REFRTRAY, 0, (LPARAM)msg->hwnd);
		}
	}
	return CallNextHookEx(_hWndProc, nCode, wParam, lParam);
}

BOOL DLLIMPORT RegisterHook(HMODULE hLib) {
	_hMouse = SetWindowsHookEx(WH_MOUSE, (HOOKPROC)MouseProc, hLib, 0);
	_hWndProc = SetWindowsHookEx(WH_CALLWNDPROCRET, (HOOKPROC)CallWndRetProc, hLib, 0);
	if (_hMouse == NULL || _hWndProc == NULL) {
		UnRegisterHook();
		return FALSE;
	}
	return TRUE;
}

void DLLIMPORT UnRegisterHook() {
	if (_hMouse) {
		UnhookWindowsHookEx(_hMouse);
		_hMouse = NULL;
	}
	if (_hWndProc) {
		UnhookWindowsHookEx(_hWndProc);
		_hWndProc = NULL;
	}
}
